﻿using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Services.Localization;
using DotNetNuke.Common;

namespace Disgrafic.DNN.SKOWrapper
{
	partial class Settings : ModuleSettingsBase
	{
		ModuleController mc = new ModuleController();

		bool TokenChanged
		{
			get
			{
				if (ViewState["tokenchanged"] != null)
					return bool.Parse(ViewState["tokenchanged"].ToString());
				else
					return false;
			}
			set
			{
				ViewState["tokenchanged"] = value;
			}
		}
		string XmlHelp
		{
			get
			{
				if (ViewState["xml"] == null)
					return "";
				else
					return ViewState["xml"].ToString();
			}
			set
			{
				ViewState["xml"] = value;
			}
		}

		public override void LoadSettings()
		{
			if (!Page.IsPostBack)
			{
				// localize grid
				Localization.LocalizeDataGrid(ref dgFields, LocalResourceFile);

				LoadSkinObjectTokens();

				if (Settings["token"] != null)
				{
					if ((ddlTokens.Items.FindByValue(Settings["token"].ToString()) != null))
					{
						ddlTokens.SelectedValue = Settings["token"].ToString();
						LoadSkinObjectProperties();
					}
				}
				BindAttributes();
			}
		}

		public override void UpdateSettings()
		{
			UpdateToken();
		}

		#region Event handlers
		protected void ddlTokens_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			if (Settings["token"] != null &&
				Settings["token"].ToString() != "" &&
				ddlTokens.SelectedValue != "" &&
				Settings["token"].ToString() != ddlTokens.SelectedValue &&
				dgFields.Items.Count > 0)
			{
				// add warning to button and set flag to changed
				// => the token has changed so if user adds a new attribute we'll have to remove
				// previous ones
				TokenChanged = true;
			}
			else
				TokenChanged = false;

			LoadSkinObjectProperties();
		}

		protected void ddlProperty_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			lblPropertyHelp.Text = "";
			txtValue.Visible = true;
			ddlValue.Visible = false;

			if (ddlProperty.SelectedValue != "" && XmlHelp != "")
			{
				LoadPropertyFromXml();
			}
		}

		protected void chkShowAll_CheckedChanged(object sender, System.EventArgs e)
		{
			LoadSkinObjectProperties();
		}

		protected void dgFields_ItemCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e)
		{
			switch (e.CommandName)
			{
				case "Delete":
					mc.DeleteModuleSetting(ModuleId, e.CommandArgument.ToString());
					BindAttributes();
					break;
			}
		}

		protected void dgFields_ItemDataBound(object sender, DataGridItemEventArgs e)
		{
			if (e.Item.ItemType == ListItemType.Item)
			{
				LinkButton lnkDelete = (LinkButton)e.Item.FindControl("lnkDelete");
				DotNetNuke.UI.Utilities.ClientAPI.AddButtonConfirm(lnkDelete, Localization.GetString("DeleteItem", Localization.SharedResourceFile));
			}
		}

		protected void cmdAdd_Click(object sender, System.EventArgs e)
		{
			if (ddlTokens.SelectedValue == "" || ddlProperty.SelectedValue == "")
			{
				lblErrorMessage.Text = Localization.GetString("InvalidProperty", LocalResourceFile);
				return;
			}
			if (TokenChanged)
			{
				mc.DeleteModuleSettings(ModuleId);
				TokenChanged = false;
			}

			UpdateToken();
			try
			{
				if (txtValue.Visible)
					mc.UpdateModuleSetting(ModuleId, ddlProperty.SelectedValue, txtValue.Text);
				else
					mc.UpdateModuleSetting(ModuleId, ddlProperty.SelectedValue, ddlValue.SelectedValue);
				ddlProperty.SelectedValue = "";
				txtValue.Text = "";
			}
			catch
			{
			}
			BindAttributes();
		}

		protected void cmdTest_Click(object sender, System.EventArgs e)
		{
			SKOWrapper.Utils.LoadSkinObject(this, pnlTest, Settings);
		}

		protected void Page_PreRender(object sender, System.EventArgs e)
		{
			if (TokenChanged)
				AddButtonWarning();
			else
				cmdAdd.Attributes.Remove("onclick");
		}
		#endregion

		#region Helpers
		private void LoadSkinObjectTokens()
		{
			// get all installed skinobjects
			Dictionary<string, SkinControlInfo> controls = SkinControlController.GetSkinControls();
			foreach (SkinControlInfo ctl in controls.Values)
			{
				ddlTokens.Items.Add(new ListItem(ctl.ControlKey, ctl.ControlKey));
			}
			ddlTokens.Items.Insert(0, new ListItem("<" + Localization.GetString("Not_Specified") + ">", ""));
		}

		private void LoadSkinObjectProperties()
		{
			string key = ddlTokens.SelectedValue;

			if (string.IsNullOrEmpty(key))
				return;

			SkinControlInfo skoInfo = SkinControlController.GetSkinControlByKey(key);
			if (skoInfo == null)
				return;

			// get a reference to the help file if it exists
			LoadXmlHelpFile(skoInfo);

			if (XmlHelp != "" && !chkShowAll.Checked)
			{
				// Load properties from xml file
				LoadPropertiesFromXml(skoInfo);
			}
			else
			{
				// Load properties from reflection
				LoadPropertiesFromReflection(skoInfo);
			}

			ddlValue.Visible = false;
		}

		private void LoadPropertiesFromXml(SkinControlInfo skoInfo)
		{
			try
			{
				XmlDocument xmlDoc = new XmlDocument();
				xmlDoc.Load(XmlHelp);

				ddlProperty.Items.Clear();
				ddlProperty.Items.Add(new ListItem("<" + Localization.GetString("Not_Specified") + ">", ""));
				foreach (XmlNode xmlSetting in xmlDoc.SelectNodes("//Settings/Setting"))
				{
					XmlNode name = xmlSetting.SelectSingleNode("Name");
					if (name != null)
						ddlProperty.Items.Add(new ListItem(name.InnerText, name.InnerText));
				}
			}
			catch
			{
				LoadPropertiesFromReflection(skoInfo);
			}
		}

		private void LoadPropertiesFromReflection(SkinControlInfo skoInfo)
		{
			Control sko = default(Control);
			sko = LoadControl(Globals.ApplicationPath + "/" + skoInfo.ControlSrc);

			ddlProperty.Items.Add(new ListItem("<" + Localization.GetString("Not_Specified") + ">", ""));

			PropertyInfo[] props = null;
			BindingFlags flags = BindingFlags.Instance | BindingFlags.Public;
			if (!chkShowAll.Checked)
				flags = flags | BindingFlags.DeclaredOnly;

			if (sko is UserControl)
				props = sko.GetType().BaseType.GetProperties(flags);
			else
				props = sko.GetType().GetProperties(flags);

			System.Array.Sort(props, new PropertyInfoComparer());
			foreach (PropertyInfo pi in props)
			{
				ddlProperty.Items.Add(new ListItem(pi.Name, pi.Name));
			}
		}

		private void LoadXmlHelpFile(SkinControlInfo skoInfo)
		{
			string xmlPath = Globals.ApplicationPath + "/" + skoInfo.ControlSrc.Replace(".ascx", ".xml");

			if (System.IO.File.Exists(Server.MapPath(xmlPath)))
			{
				XmlHelp = Server.MapPath(xmlPath);
				ddlProperty.AutoPostBack = true;
			}
			else
			{
				XmlHelp = "";
				ddlProperty.AutoPostBack = false;
			}
		}

		private void LoadPropertyFromXml()
		{
			try
			{
				XmlDocument xmlDoc = new XmlDocument();
				xmlDoc.Load(XmlHelp);
				XmlNode xmlSetting = xmlDoc.SelectSingleNode("//Settings/Setting[Name='" + ddlProperty.SelectedValue + "']");

				// set the help
				LoadPropertyHelp(xmlSetting);

				// set the values
				LoadProperyValues(xmlSetting);
			}
			catch
			{ }
		}

		private void LoadProperyValues(XmlNode xmlSetting)
		{
			if (xmlSetting != null)
			{
				string strValue = xmlSetting.SelectSingleNode("Value").InnerText;
				switch (strValue)
				{
					case "":
						break;
					case "[TABID]":
						TabController objTabs = new TabController();
						ddlValue.Items.Clear();
						foreach (TabInfo objTab in objTabs.GetTabsByPortal(PortalId).AsList())
						{
							ddlValue.Items.Add(new ListItem(objTab.TabName, objTab.TabID.ToString()));
						}

						ddlValue.Items.Insert(0, "<" + Localization.GetString("Not_Specified") + ">");
						ddlValue.Visible = true;
						txtValue.Visible = false;
						break;
					default:
						string[] arrValues = (strValue + ",").Split(',');
						ddlValue.Items.Clear();
						foreach (string val in arrValues)
						{
							if (!string.IsNullOrEmpty(val))
							{
								ddlValue.Items.Add(new ListItem(val, val));
							}
						}

						ddlValue.Items.Insert(0, "<" + Localization.GetString("Not_Specified") + ">");
						ddlValue.Visible = true;
						txtValue.Visible = false;
						break;
				}
			}
		}

		private void LoadPropertyHelp(XmlNode xmlSetting)
		{
			if (xmlSetting != null)
			{
				XmlNode xmlhelp = xmlSetting.SelectSingleNode("Help");
				XmlNode xmltype = xmlSetting.SelectSingleNode("Type");

				string help = "";
				if (xmltype != null && xmltype.InnerText != "")
					help = string.Format(Localization.GetString("Help1", LocalResourceFile), xmltype.InnerText);
				if (xmlhelp != null && xmlhelp.InnerText != "")
					help += "<br/>" + string.Format(Localization.GetString("Help2", LocalResourceFile), xmlhelp.InnerText);
				if (help != "")
				{
					help = Localization.GetString("Help0", LocalResourceFile) + help;
					lblPropertyHelp.Text = help;
				}
			}
		}

		private void BindAttributes()
		{
			Hashtable setts = mc.GetModuleSettings(ModuleId);
			Hashtable attr = Utils.GetAttributes(setts);

			dgFields.DataSource = attr;
			dgFields.DataBind();
		}

		private void AddButtonWarning()
		{
			DotNetNuke.UI.Utilities.ClientAPI.AddButtonConfirm(cmdAdd, Localization.GetString("ConfirmRemoveAll", LocalResourceFile));
		}

		private void UpdateToken()
		{
			mc.UpdateModuleSetting(ModuleId, "token", ddlTokens.SelectedValue);
		}
		#endregion
	}

	public class PropertyInfoComparer : IComparer
	{
		public int Compare(object x, object y)
		{
			return (new CaseInsensitiveComparer().Compare(
				((PropertyInfo)x).Name,
				((PropertyInfo)y).Name));
		}
	}
}
